cordova.define("mamp-plugin-device", function(require, exports, module) {

var argscheck = require('cordova/argscheck'),
    channel = require('cordova/channel'),
    utils = require('cordova/utils'),
    exec = require('cordova/exec'),
    cordova = require('cordova');
    accelerometer = require('cordova-plugin-device-motion.accelerometer');
    networkInformation = require('cordova-plugin-network-information.network');
    vibrator = require('cordova-plugin-vibration.notification');

var STATUS_CRITICAL = 5;
var STATUS_LOW = 20;

channel.createSticky('onMampDeviceInfoReady');
// Tell cordova channel to wait on the onMampDeviceInfoReady event
channel.waitForInitialization('onMampDeviceInfoReady');

var mampDevice = function () {

    /* BEGIN -- DeivceInfo */
    this.available = false;
    this.platform = null;
    this.version = null;
    this.uuid = null;
    this.cordova = null;
    this.model = null;
    this.manufacturer = null;
    this.isVirtual = null;
    this.serial = null;
    this.screenWidth = null;
    this.screenHeight = null;

    var me = this;

    channel.onCordovaReady.subscribe(function() {
        me.getInfo(function(info) {
            //ignoring info.cordova returning from native, we should use value from cordova.version defined in cordova.js
            //TODO: CB-5105 native implementations should not return info.cordova
            var buildLabel = cordova.version;
            me.available = true;
            me.platform = info.platform;
            me.version = info.version;
            me.uuid = info.uuid;
            me.cordova = buildLabel;
            me.model = info.model;
            me.isVirtual = info.isVirtual;
            me.manufacturer = info.manufacturer || 'unknown';
            me.serial = info.serial || 'unknown';
            me.screenWidth = info.screenWidth;
            me.screenHeight = info.screenHeight;
            channel.onMampDeviceInfoReady.fire();
        },function(e) {
            me.available = false;
            utils.alert("[ERROR] Error initializing Cordova: " + e);
        });
    });
    /* END -- DeivceInfo */

    /* BEGIN -- Battery */
    this._level = null;
    this._isPlugged = null;
    // Create new event handlers on the window (returns a channel instance)
    this.channels = {
      batterystatus:cordova.addWindowEventHandler("batterystatus"),
      batterylow:cordova.addWindowEventHandler("batterylow"),
      batterycritical:cordova.addWindowEventHandler("batterycritical")
    };
    for (var key in this.channels) {
        this.channels[key].onHasSubscribersChange = mampDevice.onHasSubscribersChange;
    }
    /* END -- Battery */
}

/**
*所有方法获取失败的回调中，错误信息结构如下：
function onError(error) {
    alert('code: '    + error.code    + '\n' +
          'message: ' + error.message + '\n');
};
*/

/* BEGIN -- Device Info methods */

/**
*设备信息成功获取的回调中，设备信息结构如下：
var onSuccess = function(deviceInfo) {
        var available = deviceInfo.available;            设备信息是否可获取
        var platform = deviceInfo.platform;              设备的系统平台。"iOS", "Android", "browser", "WinCE"等
        var version = deviceInfo.version;                设备系统的版本号
        var uuid = deviceInfo.uuid;                      设备ID, 类型为string
        var cordova = deviceInfo.cordova;                cordova版本号
        var model = deviceInfo.model;                    设备机型或浏览器版本，如"iPhone 5,1", "Chrome"等
        var isVirtual = deviceInfo.isVirtual;            当前是否运行在模拟器上，类型为bool
        var manufacturer = deviceInfo.manufacturer;      设备制造商，如"Apple", "Samsung"等
        var serial = deviceInfo.serial;                  设备序列号，仅支持安卓、MacOS平台
        var screenWidth = deviceInfo.screenWidth;        设备屏幕宽度，单位为pt
        var screenHeight = deviceInfo.screenHeight;      设备屏幕高度，单位为pt
};
*/

/**
 * 获取设备信息
 *
 * @param {Function} successCallback  成功获取设备信息的回调
 * @param {Function} errorCallback    (OPTIONAL)获取设备信息失败的回调
 */
mampDevice.prototype.getInfo = function(successCallback, errorCallback) {
    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
    exec(successCallback, errorCallback, "MAMPDevice", "getDeviceInfo", []);
};

/* END -- Device Info methods */

/* BEGIN -- Battery Methods */
function batteryHandlers() {
    return mampDevice.channels.batterystatus.numHandlers +
        mampDevice.channels.batterylow.numHandlers +
        mampDevice.channels.batterycritical.numHandlers;
}

/**
 * Event handlers for when callbacks get registered for the battery.
 * Keep track of how many handlers we have so we can start and stop the native battery listener
 * appropriately (and hopefully save on battery life!).
 */
mampDevice.onHasSubscribersChange = function() {
  // If we just registered the first handler, make sure native listener is started.
  if (this.numHandlers === 1 && batteryHandlers() === 1) {
      exec(mampDevice._status, mampDevice._error, "MAMPDevice", "startBatteryListener", []);
  } else if (batteryHandlers() === 0) {
      exec(null, null, "MAMPDevice", "stopBatteryListener", []);
  }
};

/**
 * Callback for battery status
 *
 * @param {Object} info            keys: level, isPlugged
 */
mampDevice.prototype._status = function (info) {

    if (info) {
        if (mampDevice._level !== info.level || mampDevice._isPlugged !== info.isPlugged) {
            
            if(info.level === null && mampDevice._level !== null) {
                return; // special case where callback is called because we stopped listening to the native side.
            }
            
            // Something changed. Fire batterystatus event
            cordova.fireWindowEvent("batterystatus", info);

            if (!info.isPlugged) { // do not fire low/critical if we are charging. issue: CB-4520
                // note the following are NOT exact checks, as we want to catch a transition from 
                // above the threshold to below. issue: CB-4519
                if (mampDevice._level > STATUS_CRITICAL && info.level <= STATUS_CRITICAL) { 
                    // Fire critical battery event
                    cordova.fireWindowEvent("batterycritical", info);
                }
                else if (mampDevice._level > STATUS_LOW && info.level <= STATUS_LOW) {
                    // Fire low battery event
                    cordova.fireWindowEvent("batterylow", info);
                }
            }
            mampDevice._level = info.level;
            mampDevice._isPlugged = info.isPlugged;
        }
    }
};

/**
 * Error callback for battery start
 */
mampDevice.prototype._error = function(e) {
    console.log("Error initializing Battery: " + e);
};

/**
*设备电池剩余电量成功获取的回调中，电量信息结构如下：
var onSuccess = function(batteryLevel) {
        var batteryLevel = batteryLevel;            剩余电池电量，类型为float，范围为 0 - 100，如50说明剩余电量为50%,如果值为-1，说明获取失败
};
*/

/**
* 获取当前设备电池剩余电量
*
* @param {Function} successCallback  获取设备剩余电量成功时的回调
* @param {Function} errorCallback    (OPTIONAL)获取设备电量失败时的回调
*/
mampDevice.prototype.getBatteryLevel = function(successCallback, errorCallback) {
    argscheck.checkArgs('fF', 'mampDevice.getBatteryLevel', arguments);
    exec(successCallback, errorCallback, "MAMPDevice", "getBatteryLevel", []);
};

/**
*设备电池状态与电量变化时触发的回调中，电量信息结构如下：
var onSuccess = function(batteryStatus) {
        var isPlugged = batteryStatus.isPlugged;     设备当前是否正在充电，类型为bool
        var level = batteryStatus.level              设备当前剩余电量，类型为float，范围为 0 - 100，如50说明剩余电量为50%,如果值为-1，说明获取失败
};
*/

/**
* 注册设备电池状态变化事件的回调
*
* @param {Function} batteryStatusChangedCallback     (OPTIONAL)设备电源状态变化时触发的回调。如设备从未充电变为正在充电，或从正在充电变为未充电
* @param {Function} batteryLowCallback               (OPTIONAL)设备电量低时触发的回调
* @param {Function} batteryCriticalCallback          (OPTIONAL)设备电量极低时触发的回调
*/
mampDevice.prototype.registerBatteryEvent = function(batteryStatusChangedCallback, batteryLowCallback, batteryCriticalCallback) {
    if (batteryStatusChangedCallback !== null ) {
        window.addEventListener("batterystatus", batteryStatusChangedCallback, false);
    }
    if (batteryLowCallback !== null ) {
        window.addEventListener("batterylow", batteryLowCallback, false);
    }
    if (batteryCriticalCallback !== null ) {
        window.addEventListener("batterycritical", batteryCriticalCallback, false);
    }
};
/* END -- Battery Methods */

/* BEGIN -- NetworkInformation Methods */

/**
* 获取当前网络连接状态
* @return 当前网络连接状态，类型如下:
                         UNKNOWN: "unknown",
                         ETHERNET: "ethernet",
                         WIFI: "wifi",
                         CELL_2G: "2g",
                         CELL_3G: "3g",
                         CELL_4G: "4g",
                         CELL:"cellular",
                         NONE: "none"
*/
mampDevice.prototype.getConnectionType = function() {
    return networkInformation.type;
};

/**
*设备网络连接状态变化的回调中，网络连接状态结构如下：
var onSuccess = function(networkStatus) {
        var networkStatus = networkStatus;            当前网络连接状态，类型如下:
                                                                             UNKNOWN: "unknown",
                                                                             ETHERNET: "ethernet",
                                                                             WIFI: "wifi",
                                                                             CELL_2G: "2g",
                                                                             CELL_3G: "3g",
                                                                             CELL_4G: "4g",
                                                                             CELL:"cellular",
                                                                             NONE: "none"
*/

/**
* 注册网络连接状态变化时触发的回调
*
* @param {Function} callback 网络状态从未连接变化为已连接时触发的回调
*/
mampDevice.prototype.registerNetworkChangeCallback = function(callback) {
    if (callback !== null ) {
        var onNetworkStatusChange = function(event) {
            networkInformation.getInfo(function(info) {
                callback(info);
            });
        };
        window.addEventListener("online", onNetworkStatusChange, false);
        window.addEventListener("offline", onNetworkStatusChange, false);
    }
};
/* END -- NetworkInformation Methods */

/* BEGIN -- Virbration Methods */
               
/**
 * 使设备振动指定的时长或按照给定的模式振动，也可以使设备立刻停止振动（由参数控制）.
 * !!iOS设备，参数将被忽略，设备只会振动固定时长
 *
 * @param {Integer} param               振动时长，单位为毫秒。（为0时，将立刻停止当前振动）
 *
 *
 * @param {Array of Integer} param      设备振动的模式.类型为包含int类型数值的数组。奇数位数值代表振动持续时长，偶数位数值代表停止振动的时长。
                                        如[100, 200, 300, 200],设备将振动100毫秒，等待200毫秒，振动300毫秒后停止
 */
mampDevice.prototype.vibrate = function(param) {
    vibrator.vibrate(param);
};
/* END -- Virbration Methods */

/* BEGIN -- Accelerometer Methods */

/**
*获取加速感应器状 态成功的回调中，信息如下：
var onSuccess = function(acceleration) {
        var x = acceleration.x;                             x轴上的移动量
        var y = acceleration.y                              y轴上的移动量
        var z = acceleration.z                              z轴上的移动量
        var timestamp = acceleration.timestamp              获取该加速感应器状态数据的时间戳，单位为DOMTimeStamp
};
*/

/**
*注册加速感应器状态变化回调时，设置参数如下：
var option = {
    frequency: 5000,                    加速感应器状态变化回调触发间隔，单位为毫秒。默认值为10000
};
*/
               
/**
 * 获取当前设备的加速感应器状态.
 *!! iOS设备上该接口无效，请使用registerAccelerationChangedCallback接口
 *
 * @param {Function} successCallback    成功获取加速感应器状态的回调
 * @param {Function} errorCallback      (OPTIONAL)获取加速感应器状态失败时的回调
 * @param {AccelerationOptions} options (OPTIONAL)获取加速感应器状态的参数. 
 */
mampDevice.prototype.getCurrentAcceleration = function(successCallback, errorCallback, options) {
    if (options !== null) {
        accelerometer.getCurrentAcceleration(successCallback, errorCallback, options);
    }
    else {
        accelerometer.getCurrentAcceleration(successCallback, errorCallback);
    }
};

/**
 * 注册设备加速感应器状态变化的回调.
 *
 * @param {Function} successCallback    成功获取设备加速感应器状态变化的回调
 * @param {Function} errorCallback      (OPTIONAL)注册设备加速感应器状态变化失败的回调
 * @param {AccelerationOptions} options (OPTIONAL)获取加速感应器状态的参数. 
 * @return String                       成功注册的监听事件的ID，停止监听时需要
 */
mampDevice.prototype.registerAccelerationChangedCallback = function(successCallback, errorCallback, options) {
    var id;
    if (options !== null) {
        id = accelerometer.watchAcceleration(successCallback, errorCallback, options);
    }
    else {
        id = accelerometer.watchAcceleration(successCallback, errorCallback);
    }
    return id;
}

/**
 * 停止指定的设备加速感应器状态变化监听回调.
 *
 * @param {String} id       设备加速感应器状态变化事件监听的ID.
 */
mampDevice.prototype.removeAccelerationCallback = function(id) {
    argscheck.checkArgs('fF', 'mampDevice.removeAccelerationCallback', arguments);
    accelerometer.clearWatch(id);
}
/* END -- Accelerometer Methods */

var mampDevice = new mampDevice();
module.exports = mampDevice;

});
